﻿using Microsoft.AspNetCore.Authorization;
using MyWeb.Business.Base;
using MyWeb.Common.Helper;
using MyWeb.Model;
using MyWeb.Model.Dto;
using MyWeb.Model.Models;
using MyWeb.Model.User;
using MyWeb.Repository.UnitOfWorks;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace MyWeb.Business.System.Impl
{
    public class PermissionService: BaseBusiness<Permission>, IPermissionService
    {
        private readonly SqlSugarScope _dbBase;
        public PermissionService(IUnitOfWorkManage unitOfWorkManage)
        {
            _dbBase = unitOfWorkManage.GetDbClient();
        }

        public async Task<PageModel<PermissionDto>> Get(int page = 1, string key = "", int limit = 50)
        {
            var allLinq = _dbBase.Queryable<Permission>().Where(p => p.IsDeleted != true);

            var linq = _dbBase.Queryable<Permission>()
                .Where(p => p.IsDeleted == false && p.Pid == 0 && (p.Name.Contains(key) || p.Description.Contains(key)))
                .Select(d => new PermissionDto()
                {
                    Id = d.Id,
                    Pid = d.Pid,
                    Code = d.Code,
                    Name = d.Name,
                    Type = d.Type,
                    IsHide = d.IsHide,
                    IskeepAlive = d.IskeepAlive,
                    Func = d.Func,
                    OrderSort = d.OrderSort,
                    Icon = d.Icon,
                    Description = d.Description,
                    Enabled = d.Enabled,
                    CreateId = d.CreateId,
                    CreateTime = d.CreateTime,
                    ModifyId = d.ModifyId,
                    ModifyTime = d.ModifyTime,
                    IsDeleted = d.IsDeleted
                });

            var count = linq.Count();
            var data = await linq.Skip((page - 1) * limit).Take(limit).ToListAsync();

            var ids = data.Select(a => a.Id).ToList();
            var childrens = await allLinq.Where(a => ids.Contains(a.Pid))
                .Select(d => new PermissionDto()
                {
                    Id = d.Id,
                    Pid = d.Pid,
                    Code = d.Code,
                    Name = d.Name,
                    Type = d.Type,
                    IsHide = d.IsHide,
                    IskeepAlive = d.IskeepAlive,
                    Func = d.Func,
                    OrderSort = d.OrderSort,
                    Icon = d.Icon,
                    Description = d.Description,
                    Enabled = d.Enabled,
                    CreateId = d.CreateId,
                    CreateTime = d.CreateTime,
                    ModifyId = d.ModifyId,
                    ModifyTime = d.ModifyTime,
                    IsDeleted = d.IsDeleted
                })
                .ToListAsync();
            var pids = data.Select(a => a.Pid).Distinct().ToList();
            var parents = await allLinq.Where(a => pids.Contains(a.Id)).ToListAsync();
            foreach (var item in data)
            {
                List<long> pidarr = new() { };
                var parent = parents.Where(d => d.Id == item.Pid).FirstOrDefault();

                while (parent != null)
                {
                    pidarr.Add(parent.Id);
                    parent = allLinq.Where(d => d.Id == parent.Pid).First();
                }

                pidarr.Reverse();
                pidarr.Insert(0, 0);
                item.PidArr = pidarr;

                //item.MName = apiList.FirstOrDefault(d => d.Id == item.Mid)?.LinkUrl;
                item.hasChildren = childrens.Where(d => d.Pid == item.Id).Any();
                item.Children = childrens.Where(d => d.Pid == item.Id).ToList();
            }

            var pageModel = new PageModel<PermissionDto>(page, count, limit, data);

            return pageModel;
        }
        public async Task<List<PermissionDto>> GetTreeTable(long pid = 0, string key = "")
        {
            var dataList = await _dbBase.Queryable<Permission>().Where(p => p.IsDeleted == false).ToListAsync();

            var data = dataList
                .Where(d => d.IsDeleted == false && d.Pid == pid && (d.Name.Contains(key) || d.Description.Contains(key)))
                .Select(d=> new PermissionDto()
                {
                    Id = d.Id,
                    Pid = d.Pid,
                    Code = d.Code,
                    Name = d.Name,
                    Type = d.Type,
                    IsHide = d.IsHide,
                    IskeepAlive = d.IskeepAlive,
                    Func = d.Func,
                    OrderSort = d.OrderSort,
                    Icon = d.Icon,
                    Description = d.Description,
                    Enabled = d.Enabled,
                    CreateId = d.CreateId,
                    CreateTime = d.CreateTime,
                    ModifyId = d.ModifyId,
                    ModifyTime = d.ModifyTime,
                    IsDeleted = d.IsDeleted
                })
                .OrderBy(d => d.OrderSort)
                .ToList();

            foreach (var item in data)
            {
                List<long> pidarr = new() { };
                var parent = dataList.FirstOrDefault(d => d.Id == item.Pid);

                while (parent != null)
                {
                    pidarr.Add(parent.Id);
                    parent = dataList.FirstOrDefault(d => d.Id == parent.Pid);
                }

                pidarr.Reverse();
                pidarr.Insert(0, 0);
                item.PidArr = pidarr;

                //item.MName = apiList.FirstOrDefault(d => d.Id == item.Mid)?.LinkUrl;
                item.hasChildren = dataList.Where(d => d.Pid == item.Id).Any();
            }

            return data;
        }
        public async Task<PermissionTree> GetPermissionTree(long pid = 0)
        {
            var permissionTrees = await _dbBase.Queryable<Permission>()
                .Where(t => t.IsDeleted == false)
                .Select(p => new PermissionTree
                {
                    id = p.Id,
                    label = p.Name,
                    pid = p.Pid,
                    order = p.OrderSort,
                    disabled = p.IsHide,
                    type = p.Type

                })
                .ToListAsync();

            PermissionTree rootRoot = new PermissionTree()
            {
                id = 0,
                pid = 0,
                order = 0,
                label = ""
            };
            RecursionHelper<PermissionTree>.LoopToAppendChildren(permissionTrees, rootRoot, pid);

            return rootRoot;
        }
        public async Task<NavigationBar> GetNavigationBar(long uid = 12)
        {
            //根据用户Id获取角色Id
            var roles = await _dbBase.Queryable<UserRole>()
                .Where(t => t.IsDeleted == false && t.UserId == uid)
                .Select(t => new { V = t.RoleId })
                .Distinct().ToListAsync();

            List<long> roleIds = new List<long>();
            foreach (var r in roles)
            {
                roleIds.Add(r.V);
            }


            //根据角色Id获取菜单
            var pid = await _dbBase.Queryable<RoleModulePermission>()
                .Where(d => d.IsDeleted == false && roleIds.Contains(d.RoleId))
                .Select(d => new { V = d.PermissionId })
                .Distinct()
                .ToListAsync();

            List<long> pids = new List<long>();
            foreach (var p in pid)
            {
                pids.Add(p.V);
            }

            var permissionTrees = await _dbBase.Queryable<Permission>()
                .Where(t => pids.Contains(t.Id) && t.IsDeleted == false)
                .Select(p => new NavigationBar
                {
                    id = p.Id,
                    code = p.Code,
                    name = p.Name,
                    pid = p.Pid,
                    order = p.OrderSort,
                    path = p.Code,
                    iconCls = p.Icon,
                    Func = p.Func,
                    IsHide = p.IsHide,
                    Type = p.Type,
                    meta = new NavigationBarMeta
                    {
                        requireAuth = true,
                        title = p.Name,
                        NoTabPage = p.IsHide,
                        keepAlive = p.IskeepAlive
                    }
                })
                .ToListAsync();

            NavigationBar rootRoot = new NavigationBar()
            {
                id = 0,
                pid = 0,
                order = 0,
                name = "根节点",
                path = "",
                iconCls = "",
                meta = new NavigationBarMeta(),

            };
            RecursionHelper<NavigationBar>.LoopToAppendChildren(permissionTrees, rootRoot, 0);

            return rootRoot;
        }
        public async Task<List<long>> GetRoleNavigationBar(long rid = 25)
        {
            //根据角色Id获取菜单
            var rids = await _dbBase.Queryable<RoleModulePermission>()
                .Where(d => d.IsDeleted == false && d.RoleId == rid)
                .Select(d => d.PermissionId)
                .Distinct()
                .ToListAsync();
            if(rids.Count <= 0)
            {
                return new List<long>();
            }
            //List<long> pids = new List<long>();
            //foreach (var p in pid)
            //{
            //    pids.Add(p.V);
            //}

            var per = await _dbBase.Queryable<Permission>()
                .Where(p => rids.Contains(p.Id) && p.IsDeleted == false)
                .ToListAsync();

            List<long> ids = per.Select(i => i.Id).ToList();
            var pids = per.Select(i => i.Pid).ToList().Distinct();
            foreach(var pid in pids)
            {
                ids.Remove(pid);
            }

            //var pids = await _dbBase.Queryable<Permission>()
            //    .Where(p => rids.Contains(p.Id) && p.IsDeleted == false)
            //    .Select(p => p.Id)
            //    .ToListAsync();

            return ids;
        }
        public async Task<object> PutPermission(AssignView assign)
        {
            await _dbBase.BeginTranAsync();
            try
            {
                //删除原数据
                await _dbBase.Updateable<RoleModulePermission>().SetColumns(r => r.IsDeleted == true).Where(r => r.RoleId == assign.rid).ExecuteCommandAsync();

                var permissions = await _dbBase.Queryable<Permission>().Where(d => d.IsDeleted == false).ToListAsync();

                var rolePermissions = new List<RoleModulePermission>();

                if (assign.pids is not null)
                {
                    rolePermissions = GetRMP(assign.pids, permissions, assign.rid);
                }

                var num = await _dbBase.Insertable(rolePermissions).ExecuteReturnSnowflakeIdListAsync();

                await _dbBase.CommitTranAsync();

                return num;
            }
            catch
            {
                await _dbBase.RollbackTranAsync();
                throw;
            }
        }
        public async Task<bool> DelPermission(long id)
        {
            await _dbBase.BeginTranAsync();
            try
            {
                var per = await _dbBase.Queryable<Permission>().Where(p => p.Id == id).Select(p=>p.Id).ToListAsync();
                
                while(per.Count > 0)
                {
                    await _dbBase.Updateable<Permission>().SetColumns(p => p.IsDeleted == true).Where(p => per.Contains(p.Id)).ExecuteCommandAsync();

                    per = await _dbBase.Queryable<Permission>().Where(p => per.Contains(p.Pid)).Select(p => p.Id).ToListAsync();
                }
                await _dbBase.CommitTranAsync();
                return true;
            }
            catch
            {
                await _dbBase.RollbackTranAsync();
                throw;
            }
        }
        public async Task<bool> InsertPermission(Permission per,SysUserInfo? userInfo)
        {
            await _dbBase.BeginTranAsync();
            try
            {
                per.CreateTime = DateTime.Now;
                per.CreateId = userInfo.Id;
                per.CreateBy = userInfo.LoginName;
                await _dbBase.Insertable(per).ExecuteReturnSnowflakeIdAsync();

                await _dbBase.CommitTranAsync();
                return true;
            }
            catch
            {
                await _dbBase.RollbackTranAsync();
                throw;
            }
        }
        public async Task<bool> UpdatePermission(Permission per, SysUserInfo? userInfo)
        {
            await _dbBase.BeginTranAsync();
            try
            {
                var p = new Permission()
                {
                    Code = per.Code,
                    Name = per.Name,
                    Type = per.Type,
                    IsHide = per.IsHide,
                    IskeepAlive = per.IskeepAlive,
                    Func = per.Func,
                    OrderSort = per.OrderSort,
                    Icon = per.Icon,
                    Pid = per.Pid,
                    Description = per.Description,
                    Enabled = per.Enabled,
                    ModifyId = userInfo.Id,
                    ModifyBy = userInfo.LoginName,
                    ModifyTime = DateTime.Now
                };
                await _dbBase.Updateable(p).Where(p=>p.Id == per.Id).ExecuteCommandAsync();

                await _dbBase.CommitTranAsync();
                return true;
            }
            catch
            {
                await _dbBase.RollbackTranAsync();
                throw;
            }
        }
        public async Task<List<PermissionListDto>> GetPermissionList()
        {
            var data = await _dbBase.Queryable<Permission>()
                .Where(p => p.IsDeleted == false && p.Enabled == true && p.Type == 1)
                .Select(p => new PermissionListDto()
                {
                    Id = p.Id,
                    Code = p.Code,
                    Name = p.Name
                })
                .ToListAsync();
            return data;
        }

        private List<RoleModulePermission> GetRMP(List<long> pids,List<Permission> permissions,long rid)
        {
            var rolePermissions = new List<RoleModulePermission>();
            foreach (var pid in pids)
            {
                var roleP = new RoleModulePermission();
                var per = permissions.Find(p => p.Id == pid);

                if (!pids.Contains(per.Pid) && per.Pid > 0)
                {
                    rolePermissions.AddRange(GetRMP(new List<long>() { per.Pid }, permissions, rid));
                }

                roleP.RoleId = rid;
                roleP.ModuleId = per.Mid.HasValue ? per.Mid.GetValueOrDefault() : long.MinValue;
                roleP.PermissionId = pid;
                roleP.IsDeleted = false;
                roleP.CreateBy = "";
                roleP.CreateId = 0;
                roleP.CreateTime = _dbBase.GetDate();

                rolePermissions.Add(roleP);
            }
            return rolePermissions;
        }
    }
}
